﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SignalEdgeDetection
{
    public partial class Form1 : Form
    {
        // 信号配置
        private List<SignalConfig> _signals = new List<SignalConfig>();
        private CancellationTokenSource _cts;
        private Random _rnd = new Random();

        // UI控件
        private DataGridView dgvSignals;
        private Button btnStart;
        private Button btnStop;
        private Panel signalGraphPanel;
        private Label lblStatus;
        private Label lblStats;
        private System.Windows.Forms.Timer uiUpdateTimer;

        public Form1()
        {
            InitializeComponent();
            InitializeSignals();
            SetupUI();
        }

        private void InitializeSignals()
        {
            _signals = new List<SignalConfig>
            {
                new SignalConfig("DI1", "Start Button", true, 50),    // 常开信号
                new SignalConfig("DI2", "Emergency Stop", false, 100), // 常闭信号
                new SignalConfig("DI3", "Sensor A", true, 80),
                new SignalConfig("DI4", "Sensor B", false, 120)
            };
        }

        private void SetupUI()
        {
            this.Text = "信号边沿检测监控系统";
            this.Size = new Size(900, 600);
            this.BackColor = Color.FromArgb(240, 240, 240);
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;

            // 数据表格
            dgvSignals = new DataGridView {
                Location = new Point(20, 20),
                Size = new Size(550, 200),
                BackgroundColor = Color.White,
                RowHeadersVisible = false,
                AutoGenerateColumns = false,
                AllowUserToAddRows = false,
                ReadOnly = true,
                SelectionMode = DataGridViewSelectionMode.FullRowSelect
            };

            dgvSignals.Columns.Add(new DataGridViewTextBoxColumn {
                Name = "colName",
                HeaderText = "信号名称",
                DataPropertyName = "Name",
                Width = 120
            });
            dgvSignals.Columns.Add(new DataGridViewTextBoxColumn {
                Name = "colPin",
                HeaderText = "PLC引脚",
                DataPropertyName = "Pin",
                Width = 80
            });
            dgvSignals.Columns.Add(new DataGridViewTextBoxColumn {
                Name = "colType",
                HeaderText = "信号类型",
                DataPropertyName = "SignalType",
                Width = 100
            });
            dgvSignals.Columns.Add(new DataGridViewTextBoxColumn {
                Name = "colDebounce",
                HeaderText = "消抖时间(ms)",
                DataPropertyName = "DebounceTime",
                Width = 120
            });
            dgvSignals.Columns.Add(new DataGridViewTextBoxColumn {
                Name = "colCount",
                HeaderText = "触发次数",
                DataPropertyName = "TriggerCount",
                Width = 100
            });

            dgvSignals.DataSource = new BindingList<SignalConfig>(_signals);
            this.Controls.Add(dgvSignals);

            // 控制按钮
            btnStart = new Button {
                Text = "开始监控",
                Location = new Point(600, 30),
                Size = new Size(120, 40),
                BackColor = Color.FromArgb(70, 130, 180),
                ForeColor = Color.White,
                Font = new Font("Segoe UI", 10, FontStyle.Bold)
            };
            btnStart.Click += BtnStart_Click;
            this.Controls.Add(btnStart);

            btnStop = new Button {
                Text = "停止监控",
                Location = new Point(600, 90),
                Size = new Size(120, 40),
                BackColor = Color.FromArgb(220, 20, 60),
                ForeColor = Color.White,
                Font = new Font("Segoe UI", 10, FontStyle.Bold),
                Enabled = false
            };
            btnStop.Click += BtnStop_Click;
            this.Controls.Add(btnStop);

            // 状态标签
            lblStatus = new Label {
                Text = "状态: 已停止",
                Location = new Point(20, 240),
                Size = new Size(300, 30),
                Font = new Font("Segoe UI", 10, FontStyle.Regular)
            };
            this.Controls.Add(lblStatus);

            lblStats = new Label {
                Text = "触发统计:",
                Location = new Point(20, 280),
                Size = new Size(300, 30),
                Font = new Font("Segoe UI", 9, FontStyle.Regular)
            };
            this.Controls.Add(lblStats);

            // 信号图表面板
            signalGraphPanel = new Panel {
                Location = new Point(20, 320),
                Size = new Size(850, 200),
                BackColor = Color.White,
                BorderStyle = BorderStyle.FixedSingle
            };
            this.Controls.Add(signalGraphPanel);

            // UI更新定时器
            uiUpdateTimer = new System.Windows.Forms.Timer { Interval = 100 };
            uiUpdateTimer.Tick += UiUpdateTimer_Tick;
            uiUpdateTimer.Start();
        }

        private async void BtnStart_Click(object sender, EventArgs e)
        {
            btnStart.Enabled = false;
            btnStop.Enabled = true;
            lblStatus.Text = "状态: 运行中...";
            _signals.ForEach(s => s.TriggerCount = 0);

            _cts = new CancellationTokenSource();
            await Task.Run(() => MonitorSignals(_cts.Token), _cts.Token);
        }

        private void BtnStop_Click(object sender, EventArgs e)
        {
            _cts?.Cancel();
            btnStart.Enabled = true;
            btnStop.Enabled = false;
            lblStatus.Text = "状态: 已停止";
        }

        private void MonitorSignals(CancellationToken ct)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            while (!ct.IsCancellationRequested) {
                long cycleStart = sw.ElapsedMilliseconds;

                // 模拟读取所有信号
                foreach (var signal in _signals) {
                    // 模拟实际信号（随机生成变化）
                    bool currentState = _rnd.Next(100) < 5 ? !signal.LastState : signal.LastState;

                    // 检测信号变化
                    bool triggered = CheckEdgeDetection(signal, currentState);

                    // 如果检测到有效边沿
                    if (triggered) {
                        signal.TriggerCount++;
                        // 在实际应用中，这里会执行相应的业务逻辑
                        Debug.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] {signal.Name} 触发! (类型: {(signal.IsNO ? "常开" : "常闭")})");
                    }

                    // 保存当前状态
                    signal.LastState = currentState;
                    signal.CurrentState = currentState;
                }

                // 计算剩余时间并等待
                long elapsed = sw.ElapsedMilliseconds - cycleStart;
                if (elapsed < 50) {
                    Thread.Sleep(50 - (int)elapsed);
                }
                else {
                    // 处理超时情况
                    Debug.WriteLine($"警告: 循环超时! 执行时间: {elapsed}ms");
                }
            }
        }

        private bool CheckEdgeDetection(SignalConfig signal, bool currentState)
        {
            // 首次检测，初始化状态
            if (signal.IsFirstCheck) {
                signal.LastState = currentState;
                signal.IsFirstCheck = false;
                return false;
            }

            // 状态没有变化
            if (currentState == signal.LastState) {
                return false;
            }

            // 检测有效边沿
            bool isValidEdge = false;

            // 常闭信号：检测下降沿 (高 -> 低)
            if (!signal.IsNO && signal.LastState && !currentState) {
                isValidEdge = true;
            }
            // 常开信号：检测上升沿 (低 -> 高)
            else if (signal.IsNO && !signal.LastState && currentState) {
                isValidEdge = true;
            }

            // 检查消抖时间
            if (isValidEdge) {
                long now = Stopwatch.GetTimestamp();
                long elapsed = (now - signal.LastTriggerTime) * 1000 / Stopwatch.Frequency;

                if (elapsed < signal.DebounceTime) {
                    return false; // 消抖期内忽略
                }

                signal.LastTriggerTime = now;
                return true;
            }

            return false;
        }

        private void UiUpdateTimer_Tick(object sender, EventArgs e)
        {
            // 更新统计数据
            dgvSignals.Refresh();

            // 更新统计标签
            int totalTriggers = _signals.Sum(s => s.TriggerCount);
            lblStats.Text = $"触发统计: 总触发次数: {totalTriggers} | " +
                           string.Join(" | ", _signals.Select(s => $"{s.Name}: {s.TriggerCount}"));

            // 绘制信号图表
            DrawSignalGraph();
        }

        private void DrawSignalGraph()
        {
            using (Graphics g = signalGraphPanel.CreateGraphics()) {
                g.Clear(Color.White);
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

                // 绘制网格
                DrawGrid(g);

                // 绘制信号
                int yOffset = 30;
                int heightPerSignal = 30;

                for (int i = 0; i < _signals.Count; i++) {
                    var signal = _signals[i];
                    int yPos = yOffset + i * heightPerSignal;

                    // 绘制信号名称
                    g.DrawString($"{signal.Name} ({signal.Pin}):",
                        new Font("Consolas", 9),
                        Brushes.Black,
                        10, yPos);

                    // 绘制信号类型
                    string type = signal.IsNO ? "常开" : "常闭";
                    g.DrawString(type,
                        new Font("Consolas", 9),
                        signal.IsNO ? Brushes.Green : Brushes.Blue,
                        150, yPos);

                    // 绘制信号状态
                    Brush stateBrush = signal.CurrentState ? Brushes.Green : Brushes.Red;
                    g.FillEllipse(stateBrush, 200, yPos, 12, 12);

                    // 绘制触发指示器
                    if (signal.LastTriggerTime > 0 &&
                        (Stopwatch.GetTimestamp() - signal.LastTriggerTime) * 1000 / Stopwatch.Frequency < 1000) {
                        g.FillRectangle(Brushes.Orange, 220, yPos, 100, 12);
                        g.DrawString("触发!", new Font("Consolas", 8, FontStyle.Bold), Brushes.DarkRed, 225, yPos);
                    }
                }
            }
        }

        private void DrawGrid(Graphics g)
        {
            Pen gridPen = new Pen(Color.LightGray, 1);

            // 水平线
            for (int i = 0; i < signalGraphPanel.Height; i += 20) {
                g.DrawLine(gridPen, 0, i, signalGraphPanel.Width, i);
            }

            // 垂直线
            for (int i = 0; i < signalGraphPanel.Width; i += 20) {
                g.DrawLine(gridPen, i, 0, i, signalGraphPanel.Height);
            }
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            _cts?.Cancel();
            base.OnFormClosing(e);
        }
    }

    public class SignalConfig
    {
        public string Pin { get; set; }
        public string Name { get; set; }
        public bool IsNO { get; set; } // true=常开, false=常闭
        public int DebounceTime { get; set; } // 消抖时间(ms)
        public int TriggerCount { get; set; }
        public bool LastState { get; set; }
        public bool CurrentState { get; set; }
        public bool IsFirstCheck { get; set; } = true;
        public long LastTriggerTime { get; set; }

        public string SignalType => IsNO ? "常开" : "常闭";

        public SignalConfig(string pin, string name, bool isNO, int debounceTime)
        {
            Pin = pin;
            Name = name;
            IsNO = isNO;
            DebounceTime = debounceTime;
        }
    }
}
